# -*- coding: utf-8 -*-
import datetime
from zc_core.util.batch_gen import time_to_batch_no, batch_to_year
from pymongo import MongoClient
from pymongo.errors import DuplicateKeyError
from traceback import format_exc
from zc_core.model.items import *
from zc_core.util.encrypt_util import md5


class MongoPipeline(object):

    def __init__(self, mongo_uri, bot_name):
        self.mongo_uri = mongo_uri
        self.bot_name = bot_name
        self.client = None
        self.db_map = dict()

    @classmethod
    def from_crawler(cls, crawler):
        settings = crawler.settings
        return cls(
            mongo_uri=settings.get('MONGODB_URI'),
            bot_name=settings.get('BOT_NAME')
        )

    def open_spider(self, spider):
        _ = spider
        self.client = MongoClient(self.mongo_uri)
        # 默认初始化当前年的库
        year = str(datetime.datetime.now().year)
        self.db_map[year] = self.client['{}_{}'.format(self.bot_name, year)]

    def get_db(self, batch_no=None, year=None):
        if not batch_no and not year:
            raise Exception('批次编号与年份至少指定一个')
        if not year:
            year = batch_to_year(batch_no)
        db = self.db_map.get(year)
        if not db:
            db = self.client['{}_{}'.format(self.bot_name, year)]
            self.db_map[year] = db

        return db

    def close_spider(self, spider):
        _ = spider
        self.client.close()

    def process_item(self, item, spider):
        try:
            if not item:
                raise DropItem("drop empty item： [{}]".format(self))

            # Sku
            if isinstance(item, Sku):
                if item.validate():
                    batch_no = item.get('batchNo')
                    item['_id'] = item.pop("skuId")
                    item['offlineTime'] = 0
                    self.get_db(batch_no)['sku_{}'.format(batch_no)].update({'_id': item['_id']}, {'$set': item}, upsert=True)
                    self.get_db(batch_no)['sku_pool'].update({'_id': item['_id']}, {'$set': item}, upsert=True)
                    item['skuId'] = item.pop("_id")
                    return item
            # MissSku
            elif isinstance(item, MissSku):
                if item.validate():
                    batch_no = item.get('batchNo')
                    item['_id'] = item.pop("skuId")
                    item['offlineTime'] = 0
                    self.get_db(batch_no)['miss_sku'].update({'_id': item['_id']}, {'$set': item}, upsert=True)
                    self.get_db(batch_no)['sku_pool'].update({'_id': item['_id']}, {'$set': item}, upsert=True)
                    item['skuId'] = item.pop("_id")
                    return item
            # ItemData
            elif isinstance(item, ItemData):
                if item.validate():
                    batch_no = item.get('batchNo')
                    item['_id'] = item.pop("skuId")
                    group_list = None
                    if "groupList" in item:
                        group_list = item.pop("groupList")
                    # 保存商品数据
                    self.get_db(batch_no)['data_{}'.format(item.get('batchNo'))].update({'_id': item['_id']}, {'$set': item}, upsert=True)
                    self.get_db(batch_no)['item_data_pool'].update({'_id': item['_id']}, {'$set': item}, upsert=True)
                    self.get_db(batch_no)['sku_pool'].update({'_id': item['_id']}, {'$set': {'offlineTime': 0}}, upsert=False)
                    # 保存同款分组编号
                    if group_list and len(group_list):
                        group_list.append(item['_id'])
                        self.get_db(batch_no)['data_{}'.format(item.get('batchNo'))].update_many({'_id': {'$in': group_list}}, {'$set': {'spuId': item.get('spuId')}}, upsert=False)
                        self.get_db(batch_no)['item_data_pool'].update_many({'_id': {'$in': group_list}}, {'$set': {'spuId': item.get('spuId')}}, upsert=False)
                        self.get_db(batch_no)['sku_pool'].update_many({'_id': {'$in': group_list}}, {'$set': {'offlineTime': 0}}, upsert=False)
                    item['skuId'] = item.pop("_id")
                    return item
            # MissItemData
            elif isinstance(item, MissItemData):
                if item.validate():
                    batch_no = item.get('batchNo')
                    item['_id'] = item.pop("skuId")
                    self.get_db(batch_no)['miss_item_data'].update({'_id': item['_id']}, {'$set': item}, upsert=True)
                    self.get_db(batch_no)['item_data_pool'].update({'_id': item['_id']}, {'$set': item}, upsert=True)
                    item['skuId'] = item.pop("_id")
                    return item
            # Spu
            elif isinstance(item, Spu):
                if item.validate():
                    batch_no = item.get('batchNo')
                    item['_id'] = item.pop("spuId")
                    item['offlineTime'] = 0
                    self.get_db(batch_no)['spu_{}'.format(batch_no)].update({'_id': item['_id']}, {'$set': item}, upsert=True)
                    self.get_db(batch_no)['spu_pool'].update({'_id': item['_id']}, {'$set': item}, upsert=True)
                    item['spuId'] = item.pop("_id")
                    return item
            # SPU数据（补充）[只更新不插入]
            elif isinstance(item, SpuSupply):
                if item.validate():
                    batch_no = item.get('batchNo')
                    item['_id'] = item.pop("spuId")
                    # 保存SPU数据
                    self.get_db(batch_no)['spu_{}'.format(item.get('batchNo'))].update({'_id': item['_id']}, {'$set': item}, upsert=False)
                    self.get_db(batch_no)['spu_pool'].update({'_id': item['_id']}, {'$set': item}, upsert=False)
                    item['spuId'] = item.pop("_id")
                    return item
            # 商品数据（补充）[只更新不插入]
            elif isinstance(item, ItemDataSupply):
                if item.validate():
                    batch_no = item.get('batchNo')
                    item['_id'] = item.pop("skuId")
                    group_list = None
                    if "groupList" in item:
                        group_list = item.pop("groupList")
                    # 保存商品数据
                    self.get_db(batch_no)['data_{}'.format(item.get('batchNo'))].update({'_id': item['_id']}, {'$set': item}, upsert=False)
                    self.get_db(batch_no)['item_data_pool'].update({'_id': item['_id']}, {'$set': item}, upsert=False)
                    # 保存同款分组编号
                    if group_list and len(group_list):
                        group_list.append(item['_id'])
                        self.get_db(batch_no)['data_{}'.format(item.get('batchNo'))].update_many({'_id': {'$in': group_list}}, {'$set': {'spuId': item.get('spuId')}}, upsert=False)
                        self.get_db(batch_no)['item_data_pool'].update_many({'_id': {'$in': group_list}}, {'$set': {'spuId': item.get('spuId')}}, upsert=False)
                    item['skuId'] = item.pop("_id")
                    return item
            # 商品虚拟组
            elif isinstance(item, ItemGroup):
                if item.validate():
                    batch_no = item.get('batchNo')
                    item.get('skuIdList', []).append(item.get('skuId'))
                    self.get_db(batch_no)['data_{}'.format(item.get('batchNo'))].update_many({'_id': {'$in': item['skuIdList']}}, {'$set': {'spuId': item.get('spuId')}}, upsert=False)
                    self.get_db(batch_no)['item_data_pool'].update_many({'_id': {'$in': item['skuIdList']}}, {'$set': {'spuId': item.get('spuId')}}, upsert=False)
                    return item
            # 主订单
            elif isinstance(item, Order):
                if item.validate():
                    # 补充采购单位编号
                    order_dept = item.get('orderDept')
                    if order_dept and not item.get('deptId'):
                        item['deptId'] = md5(order_dept)
                    # 计算批次
                    batch_no = item.get('batchNo')
                    if not batch_no and 'orderTime' in item and item.get('orderTime', None):
                        # 要求：本地时间
                        order_time = item.get('orderTime', '')
                        if order_time:
                            batch_no = time_to_batch_no(order_time)
                    if batch_no:
                        # 20190710 -> 2019
                        year = str(batch_no)[:-4]
                        item['_id'] = item.pop('id')
                        self.get_db(year=year)['order_{}'.format(year)].update({'_id': item['_id']}, {'$set': item}, upsert=True)
                        item['id'] = item.pop('_id')
                    return item
            # 订单状态
            elif isinstance(item, OrderStatus):
                if item.validate():
                    # 计算批次
                    batch_no = item.get('batchNo')
                    if not batch_no and 'orderTime' in item and item.get('orderTime', None):
                        # 要求：本地时间
                        order_time = item.get('orderTime', '')
                        if order_time:
                            batch_no = time_to_batch_no(order_time)
                    # 动态集合名
                    if batch_no:
                        # 20190710 -> 2019
                        year = str(batch_no)[:-4]
                        item['_id'] = item.pop('id')
                        self.get_db(year=year)['order_{}'.format(year)].update({'_id': item['_id']}, {'$set': item}, upsert=False)
                        item['id'] = item.pop('_id')
                    return item
            # 订单明细
            elif isinstance(item, OrderItem):
                if item.validate():
                    # 补充采购单位编号
                    order_dept = item.get('orderDept')
                    if order_dept and not item.get('deptId'):
                        item['deptId'] = md5(order_dept)
                    # 计算批次
                    batch_no = item.get('batchNo')
                    if not batch_no:
                        batch_no = time_to_batch_no(item.get('orderTime'))
                    # 20190710 -> 201907
                    year = str(batch_no)[:-2]
                    item['_id'] = item.pop("id")
                    dept_id = item.get('deptId', None)
                    if not dept_id:
                        item['deptId'] = md5(item.get('orderDept', ''))
                    self.get_db(batch_no)['order_item_{}'.format(year)].update({'_id': item['_id']}, {'$set': item}, upsert=True)
                    item['id'] = item.pop("_id")
                    return item
            # 询价项目
            elif isinstance(item, Inquiry):
                if item.validate():
                    # 计算批次
                    batch_no = item.get('batchNo')
                    if not batch_no and 'publishTime' in item and item.get('publishTime', None):
                        # 要求：本地时间
                        publish_time = item.get('publishTime', '')
                        if publish_time:
                            batch_no = time_to_batch_no(publish_time)
                    if batch_no:
                        # 20190710 -> 2019
                        year = str(batch_no)[:-4]
                        item['_id'] = item.pop('projectCode')
                        self.get_db(year=year)['inquiry_{}'.format(year)].update({'_id': item['_id']}, {'$set': item}, upsert=True)
                        item['projectCode'] = item.pop('_id')
                    return item
            # 订单状态
            elif isinstance(item, InquiryStatus):
                if item.validate():
                    # 计算批次
                    batch_no = item.get('batchNo')
                    if not batch_no and 'publishTime' in item and item.get('publishTime', None):
                        # 要求：本地时间
                        publish_time = item.get('publishTime', '')
                        if publish_time:
                            batch_no = time_to_batch_no(publish_time)
                    # 动态集合名
                    if batch_no:
                        # 20190710 -> 2019
                        year = str(batch_no)[:-4]
                        item['_id'] = item.pop('projectCode')
                        self.get_db(year=year)['inquiry_{}'.format(year)].update({'_id': item['_id']}, {'$set': item}, upsert=False)
                        item['projectCode'] = item.pop('_id')
                    return item
            # 订单明细
            elif isinstance(item, InquiryItem):
                if item.validate():
                    # 计算批次
                    batch_no = item.get('batchNo')
                    if not batch_no:
                        batch_no = time_to_batch_no(item.get('publishTime'))
                    # 20190710 -> 201907
                    year = str(batch_no)[:-2]
                    item['_id'] = item.pop("itemId")
                    self.get_db(batch_no)['inquiry_item_{}'.format(year)].update({'_id': item['_id']}, {'$set': item}, upsert=True)
                    item['itemId'] = item.pop("_id")
                    return item
            # 批次
            elif isinstance(item, Batch):
                if item.validate():
                    batch_no = item.pop('batchNo')
                    item['_id'] = batch_no
                    self.get_db(batch_no)['t_batch'].update({'_id': batch_no}, {'$set': item}, upsert=True)
                    item['skuId'] = item.pop("_id")
                    return item
            # 供应商
            elif isinstance(item, Catalog):
                if item.validate():
                    batch_no = item.get('batchNo', None)
                    if not batch_no:
                        batch_no = spider.batch_no
                    item['_id'] = item.pop("catalogId")
                    self.get_db(batch_no)['cat_{}'.format(item.get('batchNo'))].update({'_id': item['_id']}, {'$set': item}, upsert=True)
                    self.get_db(batch_no)['catalog_pool'].update({'_id': item['_id']}, {'$set': item}, upsert=True)
                    item['catalogId'] = item.pop("_id")
                    return item
            # 分类商品量
            elif isinstance(item, CatSkuCount):
                if item.validate():
                    batch_no = item.get('batchNo', None)
                    if not batch_no:
                        batch_no = spider.batch_no
                    item['_id'] = item.pop("catalogId")
                    self.get_db(batch_no)['cat_{}'.format(item.get('batchNo'))].update({'_id': item['_id']}, {'$set': item}, upsert=True)
                    item['catalogId'] = item.pop("_id")
                    return item
            # 供应商
            elif isinstance(item, Supplier):
                if item.validate():
                    batch_no = item.get('batchNo', None)
                    if not batch_no:
                        batch_no = spider.batch_no
                    item['_id'] = item.pop("id")
                    self.get_db(batch_no)['supplier_{}'.format(item.get('batchNo'))].update({'_id': item['_id']}, {'$set': item}, upsert=True)
                    self.get_db(batch_no)['supplier_pool'].update({'_id': item['_id']}, {'$set': item}, upsert=True)
                    item['id'] = item.pop("_id")
                    return item
            # 品牌
            elif isinstance(item, Brand):
                if item.validate():
                    batch_no = item.get('batchNo', None)
                    if not batch_no:
                        batch_no = spider.batch_no
                    item['_id'] = item.pop("id")
                    self.get_db(batch_no)['brand_{}'.format(item.get('batchNo'))].update({'_id': item['_id']}, {'$set': item}, upsert=True)
                    self.get_db(batch_no)['brand_pool'].update({'_id': item['_id']}, {'$set': item}, upsert=True)
                    item['id'] = item.pop("_id")
                    return item
            elif isinstance(item, ItemPoolData):
                if item.validate():
                    batch_no = item.get('batchNo')
                    item['_id'] = item.pop("skuId")
                    # 保存数据
                    self.get_db(batch_no)['item_data_pool'].update({'_id': item['_id']}, {'$set': item}, upsert=True)
                    item['skuId'] = item.pop("_id")
                    return item
            elif isinstance(item, DealerItemData):
                if item.validate():
                    batch_no = item.get('batchNo')
                    item['_id'] = item.pop("skuId")
                    # 保存数据
                    self.get_db(batch_no)['dealer_{}'.format(item.get('batchNo'))].update({'_id': item['_id']},
                                                                                        {'$set': item}, upsert=True)
                    self.get_db(batch_no)['dealer_item_pool'].update({'_id': item['_id']}, {'$set': item}, upsert=True)
                    item['skuId'] = item.pop("_id")
                    return item
            # 图片采集
            elif isinstance(item, ImageItem):
                return item
        except DuplicateKeyError:
            spider.logger.debug('duplicate key error collection')
        except Exception as e:
            _ = e
            spider.logger.error(format_exc())

        return item
